/**
 * @author 带只拖鞋去流浪
 * @description 两栏布局拖拽设置大小
 */
import { defineComponent, reactive, ref, onMounted, watch, computed, onBeforeUnmount } from "vue";
import _ from 'lodash';
import styles from './index.module.scss';

/**
 * @description 判断是否为 0
 * @param {*} val
 * @returns { boolean }
 */
const isZero = val => val === 0

export default defineComponent({
    props: {
        /**
         * @description first size
         */
        firstSize: {
            type: Number,
            default: 0,
        },
        /**
         * @description second size
         */
        secondSize: {
            type: Number,
            default: 0,
        },
        /**
         * @description first min size
         */
        firstMinSize: {
            type: Number,
            default: 50
        },
        /**
         * @description second min size
         */
        secondMinSize: {
            type: Number,
            default: 50
        },
        /**
         * @description 模式
         */
        mode: {
            type: String,
            default: 'horizontal' // 'vertical'
        },
        /**
         * @description first className
         */
        firstClassName: {
            type: String,
        },
        /**
         * @description second className
         */
        secondClassName: {
            type: String,
        },
        /**
         * @description controller className
         */
        controllerClassName: {
            type: String,
        },
        /**
         * @description controller size
         */
        controllerSize: {
            type: Number,
            default: 4 // 'px'
        },
    },

    setup(props, { slots, expose, emit }) {
        const containerRef = ref(null);
        const firstContainerRef = ref(null);
        const controllerRef = ref(null);
        const secondContainerRef = ref(null);

        const state = reactive({
            /**
             * @description class suffix
             * @type {string}
             */
            classSuffix: props.mode,
        });

        /**
         * @description 响应式 props，watch 监听，本组件可修改
         * @type {object}
         */
        const reactiveProps = reactive({ ...props });
        expose(reactiveProps);  // 暴露

        _.forEach(props, (value, key) => {
            watch(() => props[key], (value) => {
                reactiveProps[key] = value;
                // 如果父组件只想改变 secondSize 时
                if(key === 'secondSize'){
                    reactiveProps.firstSize = 0;
                }
            })
        });

        watch(() => props.mode, (newValue, oldValue) => {
            if (newValue !== oldValue) {
                state.classSuffix = newValue;
                reactiveProps.firstSize = props.firstSize;
                reactiveProps.secondSize = props.secondSize;
            }
        });

        /**
         * @description 计算 firstSize
         * @return { string }
         */
        const getFirstSize = () => {
            if (isZero(reactiveProps.firstSize) && isZero(reactiveProps.secondSize)) {
                return `calc(50% - ${reactiveProps.controllerSize/2}px)`;
            }
            if (!isZero(reactiveProps.firstSize)) {
                return reactiveProps.firstSize - reactiveProps.controllerSize/2 + 'px';
            }
            if (!isZero(reactiveProps.secondSize)) {
                return `calc(100% - ${reactiveProps.secondSize + reactiveProps.controllerSize/2}px)`;
            }
        };

        /**
         * @description 计算 secondSize
         * @return { string }
         */
        const getSecondSize = () => {
            if (isZero(reactiveProps.firstSize) && isZero(reactiveProps.secondSize)) {
                return `calc(50% - ${reactiveProps.controllerSize/2}px)`;
            }
            if (!isZero(reactiveProps.firstSize)) {
                return `calc(100% - ${reactiveProps.firstSize + reactiveProps.controllerSize/2}px)`;
            }
            if (!isZero(reactiveProps.secondSize)) {
                return reactiveProps.secondSize - reactiveProps.controllerSize/2 + 'px';
            }
        };

        /**
         * @description 计算 currentFirstHeight，mode 是 vertical 时有效
         * @type { string }
         */
        const currentFirstHeight = computed(() => {
            if (reactiveProps.mode === 'vertical') {
                return getFirstSize();
            } else {
                return '100%';
            }
        });

        /**
         * @description 计算 currentSecondHeight，mode 是 vertical 时有效
         * @type { string }
         */
        const currentSecondHeight = computed(() => {
            if (reactiveProps.mode === 'vertical') {
                return getSecondSize();
            } else {
                return '100%';
            }
        });

        /**
         * @description 计算 currentFirstWidth，mode 是 horizontal 时有效
         * @type { string }
         */
        const currentFirstWidth = computed(() => {
            if (reactiveProps.mode === 'horizontal') {
                return getFirstSize();
            } else {
                return '100%';
            }
        });

        /**
         * @description 计算 currentSecondWidth，mode 是 horizontal 时有效
         * @type { string }
         */
        const currentSecondWidth = computed(() => {
            if (reactiveProps.mode === 'horizontal') {
                return getSecondSize();
            } else {
                return '100%';
            }
        });

        /**
         * @description 水平方向 mousemove event
         * @param {*} e
         * @param {Element} container
         * @param {Element} firstContainer
         * @param {Element} resize
         * @param {Element} secondContainer
         * @return { void }
         */
        const horizontalResize = ({ e, container, firstContainer, resize, secondContainer }) => {
            const startX = e.clientX;
            resize.left = resize.offsetLeft - container.offsetLeft;

            window.onmousemove = (e1) => {
                const endX = e1.clientX;

                var resizeWidth = resize.left + (endX - startX);
                const maxWidth = container.offsetWidth - resize.offsetWidth;

                // 边界限制
                const leftMinWidth = parseInt(reactiveProps.firstMinSize);
                const RightMinWidth = parseInt(reactiveProps.secondMinSize);
                if (resizeWidth < leftMinWidth) resizeWidth = leftMinWidth;
                if (resizeWidth > maxWidth - RightMinWidth) resizeWidth = maxWidth - RightMinWidth;

                resize.style.left = resizeWidth + 'px';
                reactiveProps.firstSize = resizeWidth;
                reactiveProps.secondSize = container.offsetWidth - (resize.offsetWidth + firstContainer.offsetWidth);
            }
        };

        /**
         * @description 垂直方向 mousemove event
         * @param {*} e
         * @param {Element} container
         * @param {Element} firstContainer
         * @param {Element} resize
         * @param {Element} secondContainer
         * @return { void }
         */
        const verticalResize = ({ e, container, firstContainer, resize, secondContainer }) => {
            const startY = e.clientY;
            resize.top = resize.offsetTop - container.offsetTop;

            window.onmousemove = (e1) => {
                const endY = e1.clientY;

                var resizeHeight = resize.top + (endY - startY);
                const maxHeight = container.offsetHeight - resize.offsetHeight;

                // 边界限制
                const topMinHeight = parseInt(reactiveProps.firstMinSize);
                const bottomMinHeight = parseInt(reactiveProps.secondMinSize);
                if (resizeHeight < topMinHeight) resizeHeight = topMinHeight;
                if (resizeHeight > maxHeight - bottomMinHeight) resizeHeight = maxHeight - bottomMinHeight;

                resize.style.top = resizeHeight + 'px';
                reactiveProps.firstSize = resizeHeight;
                reactiveProps.secondSize = container.offsetHeight - resize.offsetHeight - firstContainer.offsetHeight;
            }
        };

        /**
         * @description 鼠标再 resize controller 的按下事件
         * @param {*} e
         * @return { void }
         */
        const mousedownInResize = (e) => {
            const container = containerRef.value;
            const firstContainer = firstContainerRef.value;
            const resize = controllerRef.value;
            const secondContainer = secondContainerRef.value;

            // user-select: none;
            document.body.style.userSelect = 'none';

            if ('horizontal' === reactiveProps.mode) {
                horizontalResize({ e, container, firstContainer, resize, secondContainer })
            } else if ('vertical' === reactiveProps.mode) {
                verticalResize({ e, container, firstContainer, resize, secondContainer })
            }

            window.onmouseup = () => {
                window.onmousemove = null;
                window.onmouseup = null;

                // emit drag end
                emit('drag-end', {...reactiveProps});

                // user-select: auto;
                document.body.style.userSelect = 'auto';
            }
        };

        /**
         * @description 生命周期
         * @description 挂载后
         */
        onMounted(() => {
            controllerRef.value.addEventListener('mousedown', mousedownInResize, false);
        });

        /**
         * @description 生命周期
         * @description 销毁前
         */
        onBeforeUnmount(() => {
            controllerRef.value.removeEventListener('mousedown', mousedownInResize);
        });

        return () => (<div class={[styles.container, styles[state.classSuffix + '-container']]} ref={containerRef}>
            <section
                ref={firstContainerRef}
                class={[styles['first-container'], props.firstClassName]}
                style={{ height: currentFirstHeight.value, width: currentFirstWidth.value }}>
                {slots.first?.()}
            </section>
            <section
                ref={controllerRef}
                class={[styles.controller, props.controllerClassName]}
                style={{
                    [reactiveProps.mode === 'horizontal' ? 'width' : 'height']: reactiveProps.controllerSize + 'px'
                }}
            />
            <section
                ref={secondContainerRef}
                class={[styles['second-container'], props.secondClassName]}
                style={{ height: currentSecondHeight.value, width: currentSecondWidth.value }}>
                {slots.second?.()}
            </section>
        </div>)
    },
})